package code.example.base.util.concurrent.lock.countdownlatch;

import code.example.tool.LogFactory;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class ICountDownLatchAQS  implements  ICountDownLatch{

    public class Sync extends AbstractQueuedSynchronizer{
        @Override
        protected boolean tryReleaseShared(int arg) {
            for(;;) {
                int state = this.getState();
                int newState = state - 1;
                if (this.compareAndSetState(state, newState)) {
                    LogFactory.getLog().info("countdown:"+Thread.currentThread().getName()+" :count down :"+newState);
                    if(newState ==0){
                        LogFactory.getLog().info(Thread.currentThread().getName()+" :to wake up");
                        return true;
                    }else{
                        return false;
                    }
                }
            }
        }

        @Override
        protected int tryAcquireShared(int arg) {
            int state = this.getState();
            if(state == 0){
                return 1;//下一个等待共享线程unpark
            }else{
                return -1;//锁被占用
            }

        }
        public void setCount(int count){
            this.setState(count);
        }
        public void decrementCount(){
            this.releaseShared(1);
        }
    }
    Sync sync = new Sync();
    public ICountDownLatchAQS (int count){
        sync.setCount(count);
    }



    @Override
    public void countdown() {
        sync.decrementCount();
    }

    @Override
    public void await() {
        await(0,TimeUnit.SECONDS);
    }

    @Override
    public boolean await(int timeout, TimeUnit timeUnit) {
        try {
            LogFactory.getLog().info("await :to block thread: to park thread: "+Thread.currentThread().getName());
            boolean result = false;
            if(timeout >0){
                result =  sync.tryAcquireSharedNanos(1, timeUnit.toNanos(timeout));
            }else{
                sync.acquireShared(1);
            }

            LogFactory.getLog().info("to wake up:  unpark thread: "+Thread.currentThread().getName());
            return result;
        }catch (InterruptedException e){
            return false;
        }
    }
}
